/*
******************************
* Copyright by Maxic Tech                                                      *
* All rights are reserved.
******************************
*/

#ifndef __MAXIC_MT320X_H__
#define __MAXIC_MT320X_H__

#include <stdbool.h>
#include <math.h>
#include "maxic_i2c.h"

#define MAX_REGS 256
// #define MT320X_DEBUG

#define A0_VERSION
#define MT320X_REG_ENABLE 0x80
#define MT320X_REG_ATIME 0x81
#define MT320X_REG_PRATE 0x82
#define MT320X_REG_AWTIME 0x83
#define MT320X_REG_AILTL 0x84
#define MT320X_REG_AILTH 0x85
#define MT320X_REG_AIHTL 0x86
#define MT320X_REG_AIHTH 0x87
#define MT320X_REG_PILTL 0x88
#define MT320X_REG_PILTH 0x89
#define MT320X_REG_PIHTL 0x8A
#define MT320X_REG_PIHTH 0x8B
#define MT320X_REG_ALS_PERS 0x8C
#define MT320X_REG_TIME_SCALE 0x8D
#define MT320X_REG_PPULSE_NUM 0x8E
#define MT320X_REG_PLDRIVE 0x8F
#define MT320X_REG_PPLUSE_LENL 0x90
#define MT320X_REG_PPLUSE_LENH 0x91
#define MT320X_REG_GAIN_CTRL1 0x92
#define MT320X_REG_GAIN_CTRL2 0x93
#define MT320X_REG_ADATA_ALSL 0x95
#define MT320X_REG_ADATA_ALSH 0x96
#define MT320X_REG_ADATA_IRL 0x97
#define MT320X_REG_ADATA_IRH 0x98
#define MT320X_REG_PDATAL 0x99
#define MT320X_REG_PDATAH 0x9A
#define MT320X_REG_ASTATUS 0x9B
#define MT320X_REG_ADATA_CL 0x9C
#define MT320X_REG_ADATA_CH 0x9D
#define MT320X_REG_PART_ID 0xA2
#define MT320X_REG_MANU_ID 0xA3
#define MT320X_REG_GAIN_CTRL3 0XA6
#define MT320X_REG_SOFTRST 0xA8
#define MT320X_REG_PWTIME 0xA9
#define MT320X_REG_INTCTRL 0xAB
#define MT320X_REG_TESTCFG2 0xB2
#define MT320X_REG_TESTCFG4 0xB4
#define MT320X_REG_ANACFG1 0xB5
#define MT320X_REG_ANACFG3 0xB7
#define MT320X_REG_POFFSETL 0xC0
#define MT320X_REG_POFFSETH 0xC1
#define MT320X_REG_CALIB 0xD7
#define MT320X_REG_CALIBCFG 0xD9
#define MT320X_REG_ALS_INTEN 0xDE

// 0x80 reg definition
#define PON (0x01 << 0)
#define AEN (0x01 << 1)
// #define PEN  	(0x01 << 2)
#define PEN (0x01 << 2 | 0x01 << 4) // set PWEN and PEN enable at the same time
#define AWEN (0x01 << 3)
#define PWEN (0x01 << 4)

// 0x81 reg definition
#define ATIME_PER_STEP_X100 278
#define ATIME_MS(ms) (uint8_t)(((uint32_t)ms * 100 + ((uint32_t)ATIME_PER_STEP_X100 >> 1)) / (uint32_t)ATIME_PER_STEP_X100 - 1)

// 0x82 reg definition
#define PTIME_PER_STEP 88
#define PRATE_US(us) (uint8_t)(((uint32_t)us + ((uint32_t)PTIME_PER_STEP >> 1)) / PTIME_PER_STEP - 1)

// 0x83 awtime 0xa9 pwtime reg definition
#define WTIME_PER_STEP_X100 278
#define WTIME_MS(ms) (uint8_t)(((uint32_t)ms * 100 + ((uint32_t)WTIME_PER_STEP_X100 >> 1)) / (uint32_t)WTIME_PER_STEP_X100 - 1)

// 0x8C reg definition
#define ALS_PERSIST(p) (uint8_t)((p & 0x0F) << 0)
#define APERS_MASK (0x0F << 0)
#define PPERS_MASK (0x0F << 4)

// 0x8E reg definition
#define PULSE_NUM(n) (uint8_t)(n)

// 0x8F reg definition
#define PLDRIVE_0MA 0x0 << 0
#define PLDRIVE_25MA 0x1 << 0
#define PLDRIVE_37_5MA 0x2 << 0
#define PLDRIVE_50MA 0x3 << 0
#define PLDRIVE_62_5MA 0x4 << 0
#define PLDRIVE_75MA 0x5 << 0
#define PLDRIVE_87_5MA 0x6 << 0
#define PLDRIVE_100MA 0x7 << 0
#define PLDRIVE_112_5MA 0x8 << 0
#define PLDRIVE_125MA 0x9 << 0
#define PLDRIVE_137_5MA 0xa << 0
#define PLDRIVE_150MA 0xb << 0
#define PLDRIVE_162_5MA 0xc << 0
#define PLDRIVE_175MA 0xd << 0
#define PLDRIVE_187_5MA 0xe << 0
#define PLDRIVE_200MA 0xf << 0
#define VCSEL_DRV (0x0 << 4)
#define PLDRIVE_RESERVED (0x0 << 5)

// 0x90 reg definition
#define PULSE_LEN_L(us_l_8b) (us_l_8b - 2) // us_l_8b value should be larger than 2 and less than 1025

// 0x91  reg definition
#define PULSE_LEN_H(us_h_2b) us_h_2b
#define DUTY_SET(ds) (ds << 5)
#define PLUSE_LOW(plow) (plow << 6)
#define PULSE_LENH_RESERVED (0x0 << 2)

// 0x92 reg definition
#define AGAIN_0_25x (0x0 << 4)
#define AGAIN_0_50x (0x1 << 4)
#define AGAIN_1x (0x2 << 4)
#define AGAIN_2x (0x3 << 4)
#define AGAIN_4x (0x4 << 4)
#define AGAIN_8x (0x5 << 4)
#define AGAIN_16x (0x6 << 4)
#define AGAIN_32x (0x7 << 4)
#define AGAIN_64x (0x8 << 4)
#define AGAIN_128x (0x9 << 4)
#define AGAIN_256x (0xa << 4)
#define AGAIN_MSK (0xf << 4)
#define AGAIN_DEFAULT (0x7 << 0)

// 0x93 reg definition

#ifdef A0_VERSION
#define PGAIN_0_50X (0x1 << 0)
#define PGAIN_1X (0x2 << 0)
#define PGAIN_2X (0x3 << 0)
#define PGAIN_4X (0x4 << 0)
#define PGAIN_8X (0x5 << 0)
#define PGAIN_16X (0x6 << 0)
#define PGAIN_32X (0x7 << 0)
#define PGAIN_MSK (0x7 << 0)
#define GAIN_CTRL2_RESERVED (0x0 << 2)
#else
#define PGAIN_0_50X (0x0 << 0)
#define PGAIN_1X (0x1 << 0)
#define PGAIN_2X (0x2 << 0)
#define PGAIN_4X (0x3 << 0)
#define PGAIN_8X (0x4 << 0)
#define PGAIN_16X (0x5 << 0)
#define PGAIN_32X (0x6 << 0)
#define PGAIN_64X (0x7 << 0)
#define PGAIN_MSK (0x7 << 0)
#define GAIN_CTRL2_RESERVED (0x0 << 2)
#endif

// MT320X_REG_ASTATUS		0x9B
#define ASAT (0x01 << 7)
#define AINT (0x01 << 6)

// 0XA6
#define ALS_GAIN_MASK (0x03 << 2) // should add(), or some error when << or >> this mask
#define ALS_GAIN_1x (0x00 << 2)
#define ALS_GAIN_2x (0x01 << 2)
#define ALS_GAIN_4x (0x02 << 2)
#define ALS_GAIN_8x (0x03 << 2)

// 0xA8
#define POR (0x1 << 1)

// MT320X_REG_TESTCFG2     	0xB2
#define DARKIEN (0x01 << 3)
#define OSCCFG (0x03 << 1)
#define SWAP_EN (0x01 << 0)

// MT320X_REG_TESTCFG4     	0xB4
#define PCOFFSKIP (0x01 << 3)
#define PCOFFREF (0x01 << 4)

// MT320X_REG_ANACFG1     		0xB5
#define ALS_GT_CTRL (0x03 << 0)

//@MT320X_REG_ANACFG3      0xB7
#define ALS_CAP_CTRL_MSK (0x07 << 0)
#define ALS_CAP_CTRL_0 (0x00 << 0)
#define ALS_CAP_CTRL_3 (0x03 << 0)

// 0xD7 reg definition
#define CALAVG (0x1 << 7) // 1 means enable average
#define START_OFFSET_CAL (0x01 << 0)

// 0xD9 reg definition
#define BINSRCH_TARGET_3 (0x00 << 5)
#define BINSRCH_TARGET_7 (0x01 << 5)
#define BINSRCH_TARGET_15 (0x02 << 5)
#define BINSRCH_TARGET_31 (0x03 << 5)
#define BINSRCH_TARGET_63 (0x04 << 5)
#define BINSRCH_TARGET_127 (0x05 << 5)
#define BINSRCH_TARGET_255 (0x06 << 5)
#define BINSRCH_TARGET_511 (0x07 << 5)
#define BINSRCH_TARGET_MSK (0x07 << 5)

#define CALIBCFG_RESERVED (0x00 << 4)
#define AUTO_OFFSET_ADJ (0x00 << 3)

// 0xDE  @MT320X_REG_ALS_INTEN
#define AIEN (0x01 << 6)

#define CALIB_LUX_LOW 150
#define CALIB_LUX_HIGH 600

#define MT320X_MAX_OFFSET 65535

/*als setting*/
#define MAX_ALS_VALUE 0xFFFF // 65535*0.8 = 52428
#define MIN_ALS_VALUE 2
#define GAIN_SWITCH_LEVEL 2000 // this value should be low than sat/8 to forbid gain switch back
#define NUM_OF_LUX_TO_AVE 8
#define ALS_DRI_MIN_DELTA 5

/*lux calculate*/
#define LUX_IR_DIV_POINT 100
#define DGF 2824
#define A_COEF 1000 // multiply by 1000 to forbid decimal number
#define B_COEF -564
#define C_COEF 839 // A B: low ir  C D: high ir
#define D_COEF -421

enum capture_type
{
	OPEN_ALS = 1,
};

typedef struct
{
	uint8_t als_time;
	uint8_t await_time;
	uint16_t als_th_low;
	uint16_t als_th_high;
	uint8_t persistence;
	uint8_t als_gain1;
	uint8_t als_gain2;
	uint8_t als_gain;
} mt320x_parameters;

typedef struct
{
	int32_t tgproduct;
	int32_t saturation;
	int16_t als_factor;
	uint16_t photopic_raw;
	uint16_t ir_raw;
	uint16_t clear_raw;
	int32_t lux;
	int32_t avg_lux;
} mt320x_als_info;

struct mt320x_chip
{
	mt320x_als_info als_inf;
	mt320x_parameters params;
	bool als_enabled;
	bool first_als;
	bool als_is_ready;
	bool als_gain_auto;
	bool find_proper_gain;
	bool polling_mode;
};

void mt320x_process_als_data(struct mt320x_chip *mt320x_obj);
void mt320x_set_work_mode(struct mt320x_chip *mt320x_obj, int type);
void mt320x_check_chip_id(void);
int32_t mt320x_do_initialization(struct mt320x_chip *mt320x_obj);

#endif // __MAXIC_MT320X_H__
